<?php

use Co\Channel;

class Pool
{
    protected $maxConnection = 30; //最大连接
    protected $minConnection = 5; //最小连接
    protected $currentConnection; //当前正在使用连接
    protected $channel; //存放连接的对象
    protected $timeout = 1; //等待连接时间
    protected $gcTime = 3;
    protected static $instance;

    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function init()
    {
        $this->channel = new Channel($this->maxConnection);
        for ($i=0;$i<$this->minConnection; $i++) {
            $connection = $this->createConnection();
            $this->channel->push($connection);
            $this->currentConnection++;
        }
    }

    /**
     * 创建连接
     */
    public function createConnection()
    {

        try {
            $swooleMysql = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'root');
        } catch (\Exception $exception) {
            var_dump($exception->getMessage());
            die;
        }

        return [
            'obj' => $swooleMysql,
            'last_used' => time()
        ];
    }

    /**
     * 获取连接
     */
    public function getConnection()
    {
        /**
         * 1.如果连接不够要添加
         * 2.如果连接超过要等待
         */
        if ($this->channel->isEmpty()) {
            if ($this->currentConnection < $this->maxConnection) {
                $obj = $this->createConnection();
                $this->currentConnection++;
            }else{
                $obj = $this->channel->pop($this->timeout);
            }
        }else{
            $obj = $this->channel->pop();
        }
        return $obj;
    }

    /**
     * 释放连接
     */
    public function freeConnection($obj)
    {
        $this->channel->push($obj);
    }

    /**
     * 处理空闲连接
     */
    public function gcConnection()
    {
        swoole_timer_tick(120000, function () {
            if (!$this->channel->isEmpty()) {
                while (true) {
                    $obj = $this->channel->pop();
                    $lastUsedTime = $obj['last_used'];
                    if (($this->currentConnection > $this->minConnection) && time()- $lastUsedTime > $this->gcTime) {
                        $this->currentConnection--;
                    }else{
                        $this->channel->push($obj);
                    }
                }
            }
        });
    }

}